import 'dart:math';

import 'package:dio/dio.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';
import 'dart:convert';

import 'package:wanchong/conf.dart';
import 'dart:io';
import 'package:rxdart/rxdart.dart';
import 'package:wanchong/entity_factory.dart';

// import 'dart:mirrors';
/*
 * 封装 restful 请求
 *
 * GET、POST、DELETE、PATCH
 * 主要作用为统一处理相关事务：
 *  - 统一处理请求前缀；
 *  - 统一打印请求信息；
 *  - 统一打印响应信息；
 *  - 统一打印报错信息；
 */
class Http {
  String platform;
  static Http instance;
//  Options options;
  /// global dio object
  Dio _dio;
  String token = "";
  Dio _post;

  /// default options
  static const String API_PREFIX = baseUrl;
  static const int CONNECT_TIMEOUT = connectTimeOut;
  static const int RECEIVE_TIMEOUT = recvTimeOut;

  static String Plat = "";
  static String Token = "";

  /// http request methods
  static const String GET = 'get';
  static const String POST = 'post';
  static const String PUT = 'put';
  static const String PATCH = 'patch';
  static const String DELETE = 'delete';
  static final String CODE = "code";
  static Http getInstance() {
    print('getInstance');
    if (instance == null) {
      instance = Http();
    }
    return instance;
  }

  Http() {
    print("dio赋值");
    var options = new BaseOptions(
      baseUrl: API_PREFIX,
      // connectTimeout: CONNECT_TIMEOUT,
      receiveTimeout: RECEIVE_TIMEOUT,
//      contentType: new ContentType()
    );
    if (Platform.isAndroid) {
      Plat = "Android";
    } else if (Platform.isIOS) {
      Plat = "ios";
    }
    Dio dio = new Dio(options);
    dio.interceptors.add(AuthInterceptor()); // 添加 token
    dio.interceptors
        .add(LogInterceptor(requestHeader: true, requestBody: true)); //添加日志
    // print(dio);
    ///添加请求拦截添加token
    // if (Token=="") {

    // }
    //上传的dio实例

    _dio = dio;
  }
  PublishSubject<T> get<T>(
    String url, {
    params,
  }) {
    return _requestHttp<T>(url, GET, params);
  }

  PublishSubject<T> _requestHttp<T>(
    String url, [
    String method,
    FormData params,
  ]) {
    Future future;
    PublishSubject<T> publishSubject = PublishSubject<T>();

    ///添加请求之前的拦截器
    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (RequestOptions options) async {
          _dio.interceptors.requestLock.lock();
          // _dop
          if (Http.Token == "") {
            SharedPreferences _prefs = await SharedPreferences.getInstance();
            var token = _prefs.getString("token");
            if (token != null) {
              Http.Token = token;
            }
          }
          // print(Http.Token);
          _dio.interceptors.requestLock.unlock();

          options.headers["authentication"] = Http.Token;
          print(options.headers);
          return options;
        },
      ),
    );
    // _dio.interceptors.
    if (method == GET) {
      if (params != null && params.isNotEmpty) {
        future = _dio.get(url, queryParameters: params);
      } else {
        // print(_dio);
        future = _dio.get(url);
      }
    } else if (method == POST) {
      if (params != null && params.isNotEmpty) {
        future = _dio.post(url, data: params);
      } else {
        future = _dio.post(url);
      }
    } else if (method == PUT) {
      if (params != null && params.isNotEmpty) {
        future = _dio.put(url, data: params);
      } else {
        future = _dio.put(url);
      }
    } else if (method == PATCH) {
      if (params != null && params.isNotEmpty) {
        future = _dio.patch(url, data: params);
      } else {
        future = _dio.patch(url);
      }
    } else if (method == DELETE) {
      if (params != null && params.isNotEmpty) {
        future = _dio.delete(url, data: params);
      } else {
        future = _dio.delete(url);
      }
    }
    future.then((data) {
      print("---responseData----${data}-----");
      // print(data.toString().runtimeType);
      //这里要做错误处理
      //需要先过滤 error ， 根据和后台的 约定 ， 搞清楚什么是失败
      // 什么是成功  ， 这里只是根据了干货集中营的 返回 模拟了一下

      // print(json.decode(data.toString()).runtimeType);
      // var a = Map<String,dynamic>.from();
      bool err = json.decode(data.toString())["code"] != 200;
      var dataMap = json.decode(data.toString());

      var errorMsg = "";

      if (err) {
        ///重新登录
        if (dataMap[CODE] == 204) {
          //TODO 发送信息到app
        }
        errorMsg = '错误码：' + dataMap[CODE].toString() + '，' + data.toString();

        // _error(errorCallBack, dataStr);
        print("进入了自定义错误");
        // print(errorMsg);
        callError(
          publishSubject,
          MyError(dataMap[CODE], dataMap["msg"]),
        );
        // throw dataStr;
      } else {
        //这里的解析 请参照 https://www.jianshu.com/p/e909f3f936d6 , dart的字符串 解析蛋碎一地
        publishSubject
            .add(EntityFactory.generateOBJ<T>(json.decode(data.toString())));
        publishSubject.close();

        // cancelLoading(baseIntercept);
      }
    });
    // .catchError((err) {
    //   print(err);
    //   callError(publishSubject, MyError(1, err.toString()));
    // });

    return publishSubject;
  }

  ///请求错误以后 做的一些事情
  void callError(PublishSubject publishSubject, MyError error) {
    print("进入了回调错误");
    publishSubject.addError(error);
    publishSubject.close();
    // cancelLoading(baseIntercept);
    // if (baseIntercept != null) {
    //   baseIntercept.requestFailure(error.message);
    // }
  }

  //post请求
  PublishSubject<T> post<T>(
    String url, {
    params,
  }) {
    return _requestHttp<T>(url, POST, params);
  }

  //post请求
  PublishSubject<T> patch<T>(
    String url, {
    params,
  }) {
    return _requestHttp<T>(url, PATCH, params);
  }

  //post请求
  PublishSubject<T> delete<T>(
    String url, {
    params,
  }) {
    return _requestHttp<T>(url, DELETE, params);
  }

  //post请求
  PublishSubject<T> put<T>(
    String url, {
    params,
  }) {
    return _requestHttp<T>(url, PUT, params);
  }

  _generalUpload() {
    var options = new BaseOptions(
      baseUrl: API_PREFIX,
      connectTimeout: CONNECT_TIMEOUT,
      receiveTimeout: RECEIVE_TIMEOUT,
//      contentType: new ContentType()
    );
    Dio dio = Dio(options);
    // dio.interceptors.add(AuthInterceptor()); // 添加 token
    dio.interceptors
        .add(LogInterceptor(requestHeader: true, responseBody: true)); //添加日志
    _post = dio;
  }

  upload(String url, dynamic file, Function onProcess,
      Function successCallBack) async {
    // if (file.runtimeType=='Array') {

    // }
    // FormData tmp = ;
    Response response;
    if (_post == null) {
      _generalUpload();
    }
    try {
      response = await _post.post(
        url,
        data: FormData.from({"file": file}),
        onSendProgress: (received, total) {
          if (total != -1) {
            // print((received / total * 100).toStringAsFixed(0) + "%");
            onProcess(received, total);
          }
        },
      );
      var code = response.statusCode;
      var errorMsg = "";
      if (code != 200) {
        if (code == 500) {
          errorMsg = "服务器走丢了~请稍后再试";
        } else {
          errorMsg = '错误码：' + code.toString() + '，' + response.data.toString();
        }
        _error(errorMsg);
        return;
      }
      String dataStr = json.encode(response.data);
      successCallBack(dataStr);
    } on DioError catch (e) {
      if (e.type == DioErrorType.CONNECT_TIMEOUT) {
        // It occurs when url is opened timeout.
        print("连接超时");
      } else if (e.type == DioErrorType.SEND_TIMEOUT) {
        // It occurs when url is sent timeout.
        print("请求超时");
      } else if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
        //It occurs when receiving timeout
        print("响应超时");
      } else if (e.type == DioErrorType.RESPONSE) {
        // When the server response, but with a incorrect status, such as 404, 503...
        print("出现异常");
      } else if (e.type == DioErrorType.CANCEL) {
        // When the request is cancelled, dio will throw a error with this type.
        print("请求取消");
      } else {
        //DEFAULT Default error type, Some other Error. In this case, you can read the DioError.error if it is not null.
        print("未知错误");
      }
    }
  }

  // Future<String> _requestHttp(
  //   String url, [
  //   String method,
  //   FormData params,
  // ]) async {
  //   String errorMsg = '';
  //   int code;
  //   // print(params);
  //   try {
  //     Response response;

  //     ///添加请求之前的拦截器
  //     _dio.interceptors.add(
  //       InterceptorsWrapper(
  //         onRequest: (Options options) async {
  //           _dio.interceptors.requestLock.lock();
  //           // _dop
  //           if (Http.Token == "") {
  //             SharedPreferences _prefs = await SharedPreferences.getInstance();
  //             var token = _prefs.getString("token");
  //             if (token != null) {
  //               Http.Token = token;
  //             }
  //           }
  //           _dio.interceptors.requestLock.unlock();
  //           options.headers["Authorization"] = Http.Token;
  //           return options;
  //         },
  //       ),
  //     );
  //     if (method == GET) {
  //       if (params != null && params.isNotEmpty) {
  //         response = await _dio.get(url, queryParameters: params);
  //       } else {
  //         // print(_dio);
  //         response = await _dio.get(url);
  //       }
  //     } else if (method == POST) {
  //       if (params != null && params.isNotEmpty) {
  //         response = await _dio.post(url, data: params);
  //       } else {
  //         response = await _dio.post(url);
  //       }
  //     } else if (method == PATCH) {
  //       if (params != null && params.isNotEmpty) {
  //         response = await _dio.patch(url, data: params);
  //       } else {
  //         response = await _dio.patch(url);
  //       }
  //     } else if (method == DELETE) {
  //       if (params != null && params.isNotEmpty) {
  //         response = await _dio.delete(url, data: params);
  //       } else {
  //         response = await _dio.delete(url);
  //       }
  //     }
  //     code = response.statusCode;
  //     if (code != 200) {
  //       if (code == 500) {
  //         errorMsg = "服务器走丢了~请稍后再试";
  //       } else {
  //         errorMsg = '错误码：' + code.toString() + '，' + response.data.toString();
  //       }
  //       _error(errorMsg);
  //       // throw Error(response.data);
  //     }
  //     String dataStr = json.encode(response.data);
  //     Map<String, dynamic> dataMap = json.decode(dataStr);
  //     if (dataMap != null && dataMap[CODE] != 200) {
  //       errorMsg =
  //           '错误码：' + dataMap[CODE].toString() + '，' + response.data.toString();

  //       // _error(errorCallBack, dataStr);
  //       print(errorMsg);
  //       throw dataStr;
  //     }
  //     return dataMap['data'];
  //   } on DioError catch (e) {
  //     if (e.type == DioErrorType.CONNECT_TIMEOUT) {
  //       // It occurs when url is opened timeout.
  //       print("连接超时");
  //     } else if (e.type == DioErrorType.SEND_TIMEOUT) {
  //       // It occurs when url is sent timeout.
  //       print("请求超时");
  //     } else if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
  //       //It occurs when receiving timeout
  //       print("响应超时");
  //     } else if (e.type == DioErrorType.RESPONSE) {
  //       // When the server response, but with a incorrect status, such as 404, 503...
  //       print("出现异常");
  //     } else if (e.type == DioErrorType.CANCEL) {
  //       // When the request is cancelled, dio will throw a error with this type.
  //       print("请求取消");
  //     } else {
  //       //DEFAULT Default error type, Some other Error. In this case, you can read the DioError.error if it is not null.
  //       print("未知错误");
  //     }
  //   }
  // }

  _error(String error) {
    // print(error);
    Fluttertoast.showToast(
        msg: error.toString(),
        toastLength: Toast.LENGTH_SHORT,
        gravity: ToastGravity.CENTER);
  }
}

class AuthInterceptor extends Interceptor {
  @override
  onRequest(RequestOptions options) async {
    Map<String, dynamic> headers = new Map();
    headers["Accept-Charset"] = "utf-8";
    headers["Connection"] = "keep-alive";
    headers["Accept"] = "*/*";
    headers["device"] = Http.Plat;
    // if (Http.Token == "") {
    //   SharedPreferences _prefs = await SharedPreferences.getInstance();
    //   var token = _prefs.getString("token");
    //   if (token != null) {
    //     Http.Token = token;
    //   }
    // }
    // headers["authentication"] = Http.Token;
    // headers["Authorization"] = Http.Token;
    options.headers = headers;
    return super.onRequest(options);
  }

  // Future<String> _getToken() async {
  //   SharedPreferences _prefs = await SharedPreferences.getInstance();
  //   // String token =
  //   return _prefs.getString("token");
  // }
}

class MyError {
  int code;
  String message;
  MyError(this.code, this.message);
}
